/**
** This file is part of the DrvDigiSwitch.
** Developed Individually.
** All Rights Reserved.
** Unauthorized copying of this file, via any medium is strictly prohibited
** Proprietary and confidential
**
** Copyright 2023-06-11 Raiiwhen masterraii@icloud.com
** All rights reserved.
**/

#include "bsp.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>

/* 设备特殊常量定义 */
const char* EXT_PKG_HEAD = "DEVCALIB";
/* 外部硬件资源 */
extern ADC_HandleTypeDef hadc1;
extern UART_HandleTypeDef huart1;
extern TIM_HandleTypeDef htim14;

/* 内部依赖方法 */
static void InitTubeIO(void);
int EchoDump(const char *, size_t);
int EchoConfigAdc(const char *, size_t);
void GenVerInfo(uint8_t* dst, size_t lenMax);
void InitParaTable();
/* 回调列表 */
CioPair RX_CALLBACK[] = {
    {MST_READDUMP, EchoDump},
    {ADC_CALIB, EchoConfigAdc},
};
// 软件组件资源初始化
int InitBsp(void)
{
    algoFilterSmoothInit(&g_voltFilter, ADC_VAL_LEN / 2);
    algoFilterSmoothInit(&g_currFilter, ADC_VAL_LEN / 2);
    InitParaTable();
    InitTubeIO();
    configChannel(ADC_CH_EXT);
    g_isPwrOn = GPIO_PIN_RESET;
    /* 平台软件初始化 */
    CioInit(RX_CALLBACK, sizeof (RX_CALLBACK) / sizeof (CioPair));
    CioRegisterRx(RX_BUFF, RX_BUFF_MIRROR, COM_BUFF_MAX);
    CioRegisterTx(TX_BUFF, COM_BUFF_MAX);
    TaskInit();
	  /* 发送上线消息 */
	  EchoDump(NULL, 0);

	
    return ERR_SUCCESS;
}

int StartBsp(void)
{
    HAL_UART_Receive_DMA(&huart1, RX_BUFF, COM_BUFF_MAX);
    HAL_ADC_Start_DMA(&hadc1, ADC_VAL, ADC_VAL_LEN);
    HAL_TIM_Base_Start_IT(&htim14);
    __HAL_TIM_ENABLE_IT(&htim14, TIM_IT_UPDATE);

    return ERR_SUCCESS;
}

void configChannel(uint32_t ch)
{
    if (ch != ADC_CH_CURR && ch != ADC_CH_VBUS && ch != ADC_CH_EXT) {
        ch = ADC_CH_CURR;
    }

    ADC_ChannelConfTypeDef sConfig = {0};
    sConfig.Channel = ch;
    sConfig.Rank = ADC_REGULAR_RANK_1;
    sConfig.SamplingTime = ADC_SAMPLINGTIME_COMMON_1;

    HAL_ADC_Stop_DMA(&hadc1);
    if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) {
        Error_Handler();
    }
    HAL_ADC_Start_DMA(&hadc1, ADC_VAL, ADC_VAL_LEN);
}

void packPkg(pkg* src)
{
    if (src == NULL) {
        return;
    }
//    memcpy(src->head, PKG_HEAD, strlen(PKG_HEAD));
//    src->type = 1;

//    src->rcc = 0;
//    for (uint32_t idx = 0; idx < sizeof(pkg) - sizeof(src->rcc); idx++) {
//        src->rcc += *(((uint8_t*)src) + idx);
//    }
}

uint8_t validPkg(const pkg* s)
{
    if (s == NULL) {
        return HAL_ERROR;
    }
    if (memcmp(s->head, PKG_HEAD, strlen(PKG_HEAD)) == 0) {
        return HAL_OK;
    } else {
        return HAL_ERROR;
    }

}

uint32_t bk_falsh_GetPage(uint32_t addr)
{
    if (addr < (FLASH_BASE + FLASH_BANK_SIZE)) {
        /* Bank 1 */
        return (addr - FLASH_BASE) / FLASH_PAGE_SIZE;
    } else {
        /* Bank 2 */
        return (addr - (FLASH_BASE + FLASH_BANK_SIZE)) / FLASH_PAGE_SIZE;
    }
}

#define ROM_ADDR 0x0800fd00

void writeROM(const uint8_t* write_data, uint32_t data_size)
{
    uint16_t i,m,n;
    uint64_t data;
    uint32_t index;

    if(data_size == 0)return;
    if(data_size * 4 > FLASH_PAGE_SIZE)data_size = FLASH_PAGE_SIZE / 4;			// 数据大小不能大于1页的大小

// 1 解锁flash
    HAL_FLASH_Unlock();

// 2 擦除FLASH
// 初始化FLASH_EraseInitTypeDef
    FLASH_EraseInitTypeDef f;
    f.TypeErase = FLASH_TYPEERASE_PAGES;					// 擦除方式页擦除
    f.Page = bk_falsh_GetPage(ROM_ADDR);					// 擦除的起始页
    f.Banks = FLASH_BANK_1;					// 擦除的flash区域
    f.NbPages = 1;											// 擦除1页
// 设置PageError
    uint32_t PageError = 0;
// 调用擦除函数
    HAL_FLASHEx_Erase(&f, &PageError);

// 3 取反写FLASH
    n = data_size % 8;
    if(n == 0)												// 数据长度能被8整除
        m = data_size / 8 ;									// 得到写入flash的双字的个数
    else
        m = data_size / 8 + 1;

    for(i=0;i<m;i++)
    {
        data = 0;
        if(i != (m-1) || (i == (m-1) && n == 0))
        {
            *((uint8_t *)&data + 0) = write_data[0 + i*8];
            *((uint8_t *)&data + 1) = write_data[1 + i*8];
            *((uint8_t *)&data + 2) = write_data[2 + i*8];
            *((uint8_t *)&data + 3) = write_data[3 + i*8];
            *((uint8_t *)&data + 4) = write_data[4 + i*8];
            *((uint8_t *)&data + 5) = write_data[5 + i*8];
            *((uint8_t *)&data + 6) = write_data[6 + i*8];
            *((uint8_t *)&data + 7) = write_data[7 + i*8];
        }
        else
        {
            *((uint8_t *)&data + 0) = write_data[0 + i*8];
            if(n >= 2)
                *((uint8_t *)&data + 1) = write_data[1 + i*8];
            if(n >= 3)
                *((uint8_t *)&data + 2) = write_data[2 + i*8];
            if(n >= 4)
                *((uint8_t *)&data + 3) = write_data[3 + i*8];
            if(n >= 5)
                *((uint8_t *)&data + 4) = write_data[4 + i*8];
            if(n >= 6)
                *((uint8_t *)&data + 5) = write_data[5 + i*8];
            if(n >= 7)
                *((uint8_t *)&data + 6) = write_data[6 + i*8];
        }

        index = ROM_ADDR + i*8;

        HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, index, data);		// 如果不想取反写入Flash 把取反符号删除即可
    }


// 4 锁定FLASH
    HAL_FLASH_Lock();
}

void ReadROM(uint8_t* dst, uint32_t len)
{
    uint32_t index;
    for(size_t i = 0; i < len; i++) {
        index = ROM_ADDR + i;
        if (index < (FLASH_BASE + FLASH_BANK_SIZE)) {
            dst[i] = *((__IO uint8_t *)index);
        } else {
            dst[i] = 0;
        }
    }
}

uint32_t CioTxBytes(const uint8_t* tx, uint32_t len)
{
    while (huart1.gState == HAL_UART_STATE_BUSY_TX) {} // 避免DMA重入
    return HAL_UART_Transmit(&huart1, (uint8_t*)tx, len, 99);
}

void TubeDelay(uint32_t ms) { HAL_Delay(ms); }

void BspCtrlDigA(uint8_t isSet) { HAL_GPIO_WritePin(DIG_A_GPIO_Port, DIG_A_Pin, isSet ? GPIO_PIN_SET : GPIO_PIN_RESET); }
void BspCtrlDigB(uint8_t isSet) { HAL_GPIO_WritePin(DIG_B_GPIO_Port, DIG_B_Pin, isSet ? GPIO_PIN_SET : GPIO_PIN_RESET); }
void BspCtrlDigC(uint8_t isSet) { HAL_GPIO_WritePin(DIG_C_GPIO_Port, DIG_C_Pin, isSet ? GPIO_PIN_SET : GPIO_PIN_RESET); }
void BspCtrlDigD(uint8_t isSet) { HAL_GPIO_WritePin(DIG_D_GPIO_Port, DIG_D_Pin, isSet ? GPIO_PIN_SET : GPIO_PIN_RESET); }
void BspCtrlDigE(uint8_t isSet) { HAL_GPIO_WritePin(DIG_E_GPIO_Port, DIG_E_Pin, isSet ? GPIO_PIN_SET : GPIO_PIN_RESET); }
void BspCtrlDigF(uint8_t isSet) { HAL_GPIO_WritePin(DIG_F_GPIO_Port, DIG_F_Pin, isSet ? GPIO_PIN_SET : GPIO_PIN_RESET); }
void BspCtrlDigG(uint8_t isSet) { HAL_GPIO_WritePin(DIG_G_GPIO_Port, DIG_G_Pin, isSet ? GPIO_PIN_SET : GPIO_PIN_RESET); }
void BspCtrlDigDP(uint8_t isSet) { HAL_GPIO_WritePin(DIG_DP_GPIO_Port, DIG_DP_Pin, isSet ? GPIO_PIN_SET : GPIO_PIN_RESET); }
void BspCtrlDig1_1(uint8_t isSet) { HAL_GPIO_WritePin(DIG1_1_GPIO_Port, DIG1_1_Pin, isSet ? GPIO_PIN_SET : GPIO_PIN_RESET); }
void BspCtrlDig1_2(uint8_t isSet) { HAL_GPIO_WritePin(DIG1_2_GPIO_Port, DIG1_2_Pin, isSet ? GPIO_PIN_SET : GPIO_PIN_RESET); }
void BspCtrlDig1_3(uint8_t isSet) { HAL_GPIO_WritePin(DIG1_3_GPIO_Port, DIG1_3_Pin, isSet ? GPIO_PIN_SET : GPIO_PIN_RESET); }
void BspCtrlDig2_1(uint8_t isSet) { HAL_GPIO_WritePin(DIG2_1_GPIO_Port, DIG2_1_Pin, isSet ? GPIO_PIN_SET : GPIO_PIN_RESET); }
void BspCtrlDig2_2(uint8_t isSet) { HAL_GPIO_WritePin(DIG2_2_GPIO_Port, DIG2_2_Pin, isSet ? GPIO_PIN_SET : GPIO_PIN_RESET); }
void BspCtrlDig2_3(uint8_t isSet) { HAL_GPIO_WritePin(DIG2_3_GPIO_Port, DIG2_3_Pin, isSet ? GPIO_PIN_SET : GPIO_PIN_RESET); }

static void InitTubeIO(void)
{
    g_drvTubeVol.digA = BspCtrlDigA;
    g_drvTubeVol.digB = BspCtrlDigB;
    g_drvTubeVol.digC = BspCtrlDigC;
    g_drvTubeVol.digD = BspCtrlDigD;
    g_drvTubeVol.digE = BspCtrlDigE;
    g_drvTubeVol.digF = BspCtrlDigF;
    g_drvTubeVol.digG = BspCtrlDigG;
    g_drvTubeVol.digDP = BspCtrlDigDP;
    g_drvTubeVol.digEn[0] = BspCtrlDig1_1;
    g_drvTubeVol.digEn[1] = BspCtrlDig1_2;
    g_drvTubeVol.digEn[2] = BspCtrlDig1_3;
    g_drvTubeCurr = g_drvTubeVol;
    g_drvTubeCurr.digEn[0] = BspCtrlDig2_1;
    g_drvTubeCurr.digEn[1] = BspCtrlDig2_2;
    g_drvTubeCurr.digEn[2] = BspCtrlDig2_3;
    drvDigitalTubeClear(&g_drvTubeVol);
    drvDigitalTubeClear(&g_drvTubeCurr);
}

void BspReport(void) // 固定上报测量数据
{
    static int txCnt;
    FrmAdcReport frm;
    if (txCnt++ % 2) {
        frm.channelID = 0;
        frm.rawVal = g_voltRaw;
        frm.unit = g_caliberVolt.yUnit;
    } else {
        frm.channelID = 1;
        frm.rawVal = g_currRaw;
        frm.unit = g_caliberCurr.yUnit;
    }
    CioTxPkg(ADC_REPORT, &frm, sizeof(frm));
}

int EchoDump(const char * data, size_t dataLen)
{
    UNUSED(data);
    UNUSED(dataLen);
    FrmDumpMeasure dump;
    memset((void*)&dump, 0, sizeof (dump));
    /* 填充ID */
    dump.id.devID = DEVTYPE_MEASURE;
    dump.id.UUID[0] = HAL_GetUIDw0();
    dump.id.UUID[1] = HAL_GetUIDw1();
    dump.id.UUID[2] = HAL_GetUIDw2();
    GenVerInfo(dump.id.stamper, 8);
    /* 填充caliber */
    memcpy((void*)(&dump.caliber[0]), &g_caliberVolt, sizeof(algoLinearCalib));
    memcpy((void*)(&dump.caliber[1]), &g_caliberCurr, sizeof(algoLinearCalib));
    /* 填充实时测量结果 */
    dump.state[0].channelID = 0;
    dump.state[0].rawVal = g_voltRaw;
    dump.state[0].unit = g_caliberVolt.yUnit;
    dump.state[1].channelID = 0;
    dump.state[1].rawVal = g_currRaw;
    dump.state[1].unit = g_caliberCurr.yUnit;

    CioTxPkg(DEV_DUMP, &dump, sizeof(dump));
    return ERR_SUCCESS;
}

int EchoConfigAdc(const char * data, size_t dataLen)
{
    UNUSED(data);
    UNUSED(dataLen);
    pkg* rx = (pkg*)RX_BUFF;

//    if (validPkg(rx) == HAL_OK) {
//        FrmAdcCalib* calibCmd = (FrmAdcCalib*)(&(rx->data));
//        switch (calibCmd->channel) {
//            case 1: g_caliber->channel = ADC_CH_CURR; break;
//            case 2: g_caliber->channel = ADC_CH_VBUS; break;
//            case 3: g_caliber->channel = ADC_CH_EXT; break;
//            default: g_caliber->channel = ADC_CH_EXT;
//        }
//      configChannel(g_caliber->channel);
//      if (calibCmd->isClearPara) {
//          algoLinearCalib_Clear(g_caliber);
//          algoLinearCalibPoint finalPoint = {4096, calibCmd->finalVal};
//          algoLinearCalibPoint beginPoint = {0, 0};
//          algoLinearCalib_SetFinalPoint(g_caliber, finalPoint);
//          algoLinearCalib_InsertPoint(g_caliber, beginPoint);
//      } else {
//          algoLinearCalibPoint point = {g_AdcVal, calibCmd->val};
//          algoLinearCalib_InsertPoint(g_caliber, point);
//      }
//        writeROM((uint8_t*)g_caliber, sizeof (algoLinearCalib));
//    }
		
		return ERR_SUCCESS;
}

void CliPutChar(char ch) {}

void InitParaTable()
{
    uint8_t temp[256] = {0};
    ReadROM(temp, sizeof(algoLinearCalib) * 2);
    /* 电压参数初始化 */
    algoLinearCalib_Init(&g_caliberVolt, temp, sizeof (algoLinearCalib));
    if (g_caliberVolt.crc == 0) {
        // 生成默认参数表
        g_caliberVolt.tableID = 0;
        g_caliberVolt.xUnit = 0;
        g_caliberVolt.yUnit = -2;
        algoLinearCalib_SetRange(&g_caliberVolt, (dataPt){0, 0}, (dataPt){4096, 3630});
        algoLinearCalib_InsertPoint(&g_caliberVolt, (dataPt){990, 880});
    }
    /* 电流参数初始化 */
    algoLinearCalib_Init(&g_caliberCurr, temp + sizeof (algoLinearCalib), sizeof (algoLinearCalib));
    if (g_caliberCurr.crc == 0) {
        // 生成默认参数表
        g_caliberCurr.tableID = 1;
        g_caliberCurr.xUnit = 0;
        g_caliberCurr.yUnit = -2;
        algoLinearCalib_SetRange(&g_caliberCurr, (dataPt){0, 0}, (dataPt){4096, 660});
        algoLinearCalib_InsertPoint(&g_caliberCurr, (dataPt){680, 100});
    }
}
